"""
类的继承 介绍
"""

# 1. 定义一个父类 P:


class P:

    # 创建实例的初始化方法
    def __init__(self, name):
        self.name = name

    # 实例方法
    def get_info(self):
        return self.name


print(dir(P))
p = P('父类')
print(type(p))
print(p.get_info())


# 2. 定义一个类 C，作为 P 的 子类：


class C(P):
    pass


print(dir(C))
# 继承了父类的初始化方法
c = C('子类')
print(type(c))
# 继承了父类的实例方法
print(c.get_info())
# 通过子类直接调用方法并将实例传入
print(C.get_info(c))
# 通过父类直接调用方法并将子类的实例传入
print(P.get_info(c))

# 3. 如果方法名相同，子类重写父类的方法


class C2(P):

    # 和 继承的父类方法名相同
    def __init__(self, name):
        self.age = name


print(dir(C2))
c_ = C2('222')
# 通过 内置函数 dir 查看信息可知，实例 c_ 中只有 'age' 实例属性，而没有 'name' 实例属性
print(dir(c_))
print(c_.age)
# 执行下面语句将回报：AttributeError: 'C2' object has no attribute 'name' 的错误
# print(c_.name)

# 3.1 如果 方法名 相同，但是子类该方法的参数个数小于父类，子类会不会重写父类的方法？


# 父类
class P3:

    def __init__(self, name, age):
        self.name = name
        self.age = age


# 子类
class C3(P3):

    def __init__(self, sex):
        self.sex = sex


c_1 = C3(1)
# 通过内置函数 dir 可以看到实例 c_1 中的实例属性只有 'sex'，没有'name' 和 'age'
# 所以方法名 相同，但是子类该方法的参数个数大于父类，子类会重写父类的方法
print(dir(c_1))
print(c_1.sex)
# 执行如下代码将报：AttributeError: 'C3' object has no attribute 'age' 异常
# print(c_1.age)
# 执行如下代码将报：AttributeError: 'C3' object has no attribute 'name' 异常
# print(c_1.name)

# 3.2 如果 方法名 相同，但是子类该方法的参数个数大于父类，子类会不会重写父类的方法？


class P4:

    def __init__(self, name):
        self.name = name


class C4(P4):

    def __init__(self, sex, age):
        self.sex = sex
        self.age = age


c_2 = C4('sex', 11)
# 通过内置函数 dir 可以看到，实例c_2拥有 'sex' 和 'age' 实例属性，而没有 'name' 实例属性
# 所以方法名 相同，但是子类该方法的参数个数大于父类，子类会重写父类的方法
print(dir(c_2))
print(c_2.sex)
print(c_2.age)
# 执行如下代码将报：AttributeError: 'C4' object has no attribute 'name' 异常
# print(c_2.name)

# 3.3 如果方法名相同，如何让子类得到父类的实例属性呢？


class P5:

    def __init__(self, eat):
        self.eat = eat


class C5(P5):

    def __init__(self, name, age, sex):
        self.age = age
        self.sex = sex
        # 调用父类的初始化方法，这样就可以保留父类的实例属性
        P5.__init__(self, name)


c_3 = C5('cc', 33, 'man')
# 可以看到 实例 c_3 中 包含了实例属性 'age' 'sex' 和 来自父类的实例属性 'eat'
print(dir(c_3))
print(c_3)
print(c_3.age)
print(c_3.sex)
print(c_3.eat)
# 执行如下代码将会报：AttributeError: 'C5' object has no attribute 'name' 的异常
# print(c_3.name)

# 通过 supper() 快速实现继承的父类调用。但是需要注意：使用此方式只能用于单继承的场景，多继承的场景还是需要上面的写法


class C6(P5):

    def __init__(self, name, age, sex):
        self.age = age
        self.sex = sex
        # 通过 supper() 实现父类相同方法名，来继承父类的实例属性。注意此时的 self 没有传给父类的方法
        super().__init__(name)


c_4 = C6('66', 22, 'women')
print(dir(c_4))
print(c_4.sex)
print(c_4.age)
print(c_4.eat)
# 执行如下代码将会报：AttributeError: 'C6' object has no attribute 'name' 异常
# print(c_4.name)

# 4. 多继承的介绍（但是提倡单继承方式。还有Java 中类的继承只有单继承，这是不同的）


class K1:

    def foo(self):
        print('K1-foo')


class K2:

    def foo(self):
        print('K2-foo')

    def bar(self):
        print('K2-bar')


class J1(K1, K2):

    pass


class J2(K1, K2):

    def bar(self):
        print('J2-bar')


class C11(J1, J2):
    pass


# 可以通过 __mro__ 查看继承顺序
print(C11.__mro__)

c_5 = C11()
c_5.foo()
c_5.bar()

# 5. 关于 属性方法、类方法、静态方法的继承
# TODO